import { jsPDF } from "jspdf";
import CanvasTool from "./CanvasTool.js";

import compass from './compass.jpg';

let cvsIns = null; // 全局画布上下文 context
let isMapping = false;

/**
 * 初始化画布
 * @param {string} elementId 画布 ID
 */
export function initCanvas (elementId) {
  cvsIns = new CanvasTool(elementId);
}

/**
 * 开始制图
 * @param {ol-map} olMap openlayers map 对象
 * @param {object} form 绘制对象
 */
export function mapping (olMap, form) {
  isMapping = true;

  cvsIns.clearCanvas();

  drawCanvasBorder(); // 绘制画布边框

  drawTitle(form.title); // 绘制标题
  drawSubTitle(form.subtitle); // 绘制子标题
  drawAuthor(form.author); // 绘制作者
  drawCopyright(form.copyright); // 绘制版权所有
  drawTime(); // 制图时间

  drawScaleLine(form.scale); // 绘制比例尺

  drawMapBorder(); // 绘制地图边框
  drawMap(olMap, () => drawCompass()); // 绘制地图, 绘制指南针
}

/**
 * 绘制画布边框
 * @param {object} start // x,y
 */
function drawCanvasBorder (start = { x: 10, y: 10 }) {
  const width = cvsIns.getWidth() - start.x * 2;
  const height = cvsIns.getHeight() - start.y * 2;
  cvsIns.drawRect(start.x, start.y, width, height);
}

/**
 * 绘制标题
 * @param {string} text
 */
function drawTitle (text = "标题") {
  const font = {
    fontSize: 18,
  };
  const width = cvsIns.getWidth();
  const textWidth = cvsIns.getTextWidth(text, font);
  const position = {
    x: (width - textWidth) / 2,
    y: font.fontSize * 2,
    text: text,
  };

  cvsIns.drawText(position, font);
}

/**
 * 绘制副标题
 * @param {string} text
 */
function drawSubTitle (text = "副标") {
  const font = {
    fontSize: 16,
  };
  const width = cvsIns.getWidth();
  const textWidth = cvsIns.getTextWidth(text, font);
  const position = {
    x: (width - textWidth) / 2,
    y: 60,
    text: text,
  };
  cvsIns.drawText(position, font);
}

/**
 * 绘制作者
 * @param {string} text
 */
function drawAuthor (text = "作者") {
  const height = cvsIns.getHeight();
  const position = {
    x: 30,
    y: height - 60,
    text: "作者：" + text,
  };

  cvsIns.drawText(position);
}

/**
 * 绘制版权
 * @param {string} text
 */
function drawCopyright (text = "版权所有") {
  const height = cvsIns.getHeight();
  const position = {
    x: 30,
    y: height - 40,
    text: "版权所有：" + text,
  };

  cvsIns.drawText(position);
}

/**
 * 制图时间
 */
function drawTime () {
  const height = cvsIns.getHeight();
  const position = {
    x: 30,
    y: height - 20,
    text: new Date().toLocaleDateString(),
  };

  cvsIns.drawText(position);
}

function drawScaleLine (text) {
  const width = cvsIns.getWidth();
  const height = cvsIns.getHeight();

  const start = {
    x: width - 60 - cvsIns.getTextWidth(text),
    y: height - 60
  };

  const end = {
    x: width - 30,
    y: height - 60
  }

  cvsIns.drawLine(start, { x: start.x, y: start.y - 5 })
  cvsIns.drawLine(start, end);
  cvsIns.drawLine({ x: end.x, y: end.y - 5 }, end);

  const position = {
    text: `1:${text} km`,
    x: start.x,
    y: start.y + 15,
  }
  cvsIns.drawText(position);
}

/**
 * 绘制指南针
 */
function drawCompass () {
  const start = {
    x: cvsIns.getWidth() - 95,
    y: 85
  }
  cvsIns.drawImg(compass, start.x, start.y, 60, 60);
}

/**
 * 绘制地图边框
 * @param {object} start // x,y
 */
function drawMapBorder (start = { x: 30, y: 80 }) {
  const width = cvsIns.getWidth() - start.x * 2;
  const height = cvsIns.getHeight() - start.y * 2;
  cvsIns.drawRect(start.x, start.y, width, height);
}

/**
 * 绘制地图
 * @param {object} start 起始位置 x,y
 * @param {ol-map} map 地图对象
 */
export function drawMap (map, callback, start = { x: 30, y: 80 }) {
  map.once("rendercomplete", function () {
    Array.prototype.forEach.call(
      document.querySelectorAll(".ol-layer canvas"),
      function (canvas) {
        if (canvas.width > 0) {
          const opacity = canvas.parentNode.style.opacity;
          cvsIns.globalAlpha = opacity === "" ? 1 : Number(opacity);
          // 此处有跨域问题，须设置图层 source 属性 
          // 是否请求跨域操作 crossOrigin: 'Anonymous',  
          const url = canvas.toDataURL();
          let width = cvsIns.getWidth() - start.x * 2;
          let height = cvsIns.getHeight() - start.y * 2;

          const img = new Image();
          img.src = url;
          img.onload = () => {
            if (img.width > img.height) {
              height = width * img.height / img.width;
              start.y = (cvsIns.getHeight() - height) / 2;
            } else {
              width = height * img.width / img.height;
            }
            // 此处使用画布原生方法绘制图片
            cvsIns.getContext().drawImage(img, start.x, start.y, width, height);

            // 在地图之上绘制
            callback();
          }
        }
      }
    );
  });
  map.renderSync();
}

export function setPaper (width, height) {
  cvsIns.setWidth(width);
  cvsIns.setHeight(height);
}

/**
 * 下载制图图片
 * @param {string} fileName 文件名
 */
export function downloadFile (type) {
  if (isMapping) {
    const dataURL = cvsIns.getDataURL();
    if (type == 'png') {
      downloadImg(dataURL);
    } else if (type == 'pdf') {
      downloadPdf(dataURL);
    }
  } else {
    return alert('请先预览进行制图！')
  }
}

function downloadImg (dataURL, fileName = '制图') {
  const aLink = document.createElement("a");
  const blob = base64Img2Blob(dataURL);
  const evt = document.createEvent("MouseEvents");
  evt.initEvent("click", false, false); //initEvent 不加后两个参数在FF下会报错
  aLink.download = fileName;
  aLink.href = URL.createObjectURL(blob);
  aLink.dispatchEvent(evt);
}

function downloadPdf (dataURL) {
  const width = cvsIns.getWidth() / 4;
  const height = cvsIns.getHeight() / 4;
  const page = width > height ? 'landscape' : 'portrait';
  const pdf = new jsPDF(page);
  const pageWidth = pdf.getPageWidth();
  const pageHeight = pdf.getPageHeight();
  pdf.addImage(
    dataURL,
    "JPEG",
    (pageWidth - width) / 2,
    (pageHeight - height) / 2,
    width,
    height,
  );
  // pdf.autoPrint();
  pdf.save("制图.pdf");
}

/**
 * 图片 base64 转 blob 
 * @param {dataURL} dataURL 
 * @returns 
 */
function base64Img2Blob (dataURL) {
  let parts = dataURL.split(";base64,");
  let contentType = parts[0].split(":")[1];
  let raw = window.atob(parts[1]);
  var rawLength = raw.length;

  let uInt8Array = new Uint8Array(rawLength);
  for (let i = 0; i < rawLength; ++i) {
    uInt8Array[i] = raw.charCodeAt(i);
  }
  return new Blob([uInt8Array], {
    type: contentType
  });
}
